﻿module Sustainalytics.Security.Login {
    import Auth = Sustainalytics.Authentication;
    import Routing = Sustainalytics.Routing;
    import AuthData = Sustainalytics.Authentication.AuthData;

    export interface ngScope extends ng.IScope {
        changePasswordForm: any;
    }

    export class AccountController {
        public usercredentials: Auth.UserCredentials;
        public loginForm: any;
        public changePasswordForm: any;
        public $$autocomplete: any;
        public redirectTo: string;
        public err: string;
        private $routeParams: any;
        private submitClass: string;
        private submitClassLast: string;

        constructor(
            private $q: ng.IQService,
            private $timeout: ng.ITimeoutService,
            private $scope: ngScope,
            private RoutingService: Routing.IRoutingService,
            private $location: ng.ILocationService,
            private $rootScope,
            private AuthenticationService: Auth.IAuthenticationService,
            private notificationFactory: Common.INotificationFactory,
            private staticObjects: Common.IStaticObjects,
            private UserInfoService: Auth.IUserInfoService,
            private $window: any,
            private $modal: Common.IModal
        ) {
            var ctx = this;

            $scope['auth'] = this;

            ctx.$routeParams = ctx.RoutingService.getRouteParams();
            ctx.redirectTo = ctx.$location.search()['redirectTo'];

            ctx.initRouteError();

            if (ctx.$routeParams != undefined && ctx.$routeParams['tempKey'] != undefined && ctx.$routeParams['user'] != undefined) {
                ctx.init();
            }

            $scope.$watch('usercredentials.username', function () {
                if (!ctx.usercredentials)
                    return;

                if (ctx.usercredentials.autoComplete)
                    ctx.usercredentials.errorMessage = "";

                if (ctx.usercredentials.autoComplete) {
                    ctx.usercredentials.autoComplete = ctx.usercredentials.autoComplete - 1;
                }
            });

            $scope.$watch('usercredentials.password', function () {
                if (!ctx.usercredentials)
                    return;

                if (!ctx.usercredentials.autoComplete)
                    ctx.usercredentials.errorMessage = "";

                if (ctx.usercredentials.autoComplete) {
                    ctx.usercredentials.autoComplete = ctx.usercredentials.autoComplete - 1;
                }
            });

            ctx.initIpLogin();
        }

        private initIpLogin() {
            var ctx = this;
            if (ctx.$location.url() !== "/iplogin")
                return;
            console.log(ctx.$location.path());
            var promiste = ctx.AuthenticationService.loginWithIp();
            ctx.processPromiseAuthData(promiste, true);
        }

        private initRouteError() {
            var ctx = this;

            //var errCodeStr = ctx.$routeParams['err'];
            var errCodeStr = ctx.$location.search()['err'];

            if (!errCodeStr)
                return;

            var errCode = parseInt(errCodeStr);

            if (!errCode)
                return;

            if (!ctx.usercredentials) {
                ctx.usercredentials = { errorMessage: null, password: '', username: ctx.$routeParams['user'], confirmPassword: '', forgotPasswordEmail: '', rememberMe: true, autoComplete: null };
            }

            ctx.err = ctx.staticObjects.getMessageByInternalCode(errCode);
        }

        private init() {
            var ctx = this;

            ctx.usercredentials = { errorMessage: null, password: '', username: ctx.$routeParams['user'], confirmPassword: '', forgotPasswordEmail: '', rememberMe: true, autoComplete: null };

            var loginParams = "grant_type=password" +
                "&username=" + ctx.$routeParams['user'] +
                "&password=" + ctx.$routeParams['tempKey'] +
                "&client_id=clientId1";

            ctx.AuthenticationService.login(loginParams)
                .success((authData: Auth.AuthData) => {
                    if (!authData.access_token || !authData.expires_in || !authData.refresh_token) {
                        ctx.notificationFactory.error("", "Login failed!");
                    }
                    else {
                        ctx.usercredentials.errorMessage = "";
                        authData.loginTime = new Date();
                        ctx.$rootScope.authData = authData;
                        localStorage.setItem('sust_refresh_token', authData.refresh_token);

                        ctx.$timeout(() => {
                            // redirect to login if the refresh token failed
                            ctx.AuthenticationService.refreshToken().catch(reason => {
                                ctx.staticObjects.redirectToLogin();
                            });
                        }, (authData.expires_in - 5) * 1000);
                    }
                })
                .error((data, status: number, headers: (headerName: string) => string, config: ng.IRequestConfig) => {
                    localStorage.removeItem('sust_refresh_token');
                    localStorage.removeItem('sust:a:ur');
                    ctx.staticObjects.clearUserInfo();

                    var code = parseInt(data.error_description);
                    var error = data.error;
                    ctx.usercredentials.errorMessage = ctx.staticObjects.getErrorMesageByStatusCode(500, { code: code || error });

                    if (code == 1007 || error == 'ExpiredPassword') {
                        ctx.staticObjects.redirectToLink('/passwordExpired');
                    }

                    if (code == 1004 || error == 'IncorrectUsernamePasswordCombination') {
                        ctx.staticObjects.redirectToDefault(ctx.redirectTo);
                    }
                });
        }

        private reevaluateCredentials(resetMessage) {
            var ctx = this;

            if (ctx.$$autocomplete) {
                var email = ctx.$$autocomplete.getEmail();
                if (ctx.usercredentials.username || email) {
                    if (ctx.usercredentials.username !== email) {
                        ctx.usercredentials.autoComplete = (ctx.usercredentials.autoComplete || 0) + 1;
                        ctx.usercredentials.username = email;
                        if (resetMessage) {
                            ctx.usercredentials.errorMessage = "";
                        }
                    }
                }

                var password = ctx.$$autocomplete.getPassword();
                if (ctx.usercredentials.password || password) {
                    if (ctx.usercredentials.password !== password) {
                        ctx.usercredentials.autoComplete = (ctx.usercredentials.autoComplete || 0) + 1;
                        ctx.usercredentials.password = password;
                        if (resetMessage) {
                            ctx.usercredentials.errorMessage = "";
                        }
                    }
                }
            }
        }

        public login() {
            var ctx = this;

            ctx.usercredentials.errorMessage = "";
            ctx.reevaluateCredentials(false);

            var emailRegularExpression = /\w+([-+.']\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*/;
            var emailTest = emailRegularExpression.test(ctx.usercredentials.username);

            if (!emailTest) {
                ctx.usercredentials.errorMessage = "Please enter a valid email address.";
                return;
            }

            ctx.usercredentials.errorMessage = "";

            var loginParams = "grant_type=password" +
                "&username=" + ctx.usercredentials.username +
                "&password=" + ctx.usercredentials.password +
                "&client_id=clientId1";

            ctx.processLoginOutput(loginParams);
        }

        private processLoginOutput(loginParams: any) {
            var ctx = this;
            var promise = ctx.AuthenticationService.login(loginParams);
            ctx.processPromiseAuthData(promise, false);
        }

        private processPromiseAuthData(httpromise: ng.IHttpPromise<AuthData>, isIpLogin: boolean) {
            var ctx = this;
            console.log(isIpLogin);
            httpromise.success((authData: Auth.AuthData) => {
                if (!authData.access_token || !authData.expires_in || !authData.refresh_token) {
                    ctx.notificationFactory.error("", "Login failed!");
                }
                else {
                    ctx.usercredentials.errorMessage = "";
                    authData.loginTime = new Date();
                    ctx.$rootScope.authData = authData;
                    localStorage.setItem('sust_refresh_token', authData.refresh_token);

                    ctx.$timeout(() => {
                        // redirect to login if the refresh token failed
                        ctx.AuthenticationService.refreshToken().catch(reason => {
                            ctx.staticObjects.redirectToLogin();
                        });
                    }, (authData.expires_in - 5) * 1000);

                    // get ui resources
                    ctx.AuthenticationService.permissions().success(function () {
                        ctx.AuthenticationService.profile()
                            .success((userInfo: Common.IUserInfo) => {
                                if (isIpLogin) {
                                    //userInfo.email = userInfo.account + ".IPLogin@" + userInfo.account + ".com";
                                    userInfo.email = userInfo.account;
                                }

                                ctx.UserInfoService.setUserInfo(userInfo);
                                ctx.$rootScope.userInfo = userInfo;

                                ga('create',
                                    'UA-4379897-6',
                                    {
                                        'userId': ctx.$rootScope['userInfo'].userId,
                                        'cookieDomain': 'none',
                                        'name': 'globalAccess'
                                    });

                                ga('globalAccess.set', 'dimension1', ctx.$rootScope['userInfo'].userId);

                                var dateNow = new Date();
                                var dateNowString = [
                                    dateNow.getDate(), dateNow.getMonth() + 1, dateNow.getFullYear()
                                ].join("/");
                                var gaObject: any = {
                                    Date: dateNowString,
                                    AccountId: ctx.$rootScope['userInfo'].accountId,
                                    UserId: ctx.$rootScope['userInfo'].userId
                                };

                                ga('globalAccess.send',
                                    {
                                        'hitType': 'event',
                                        'eventCategory': 'Login',
                                        'eventAction': 'User logged in',
                                        'eventLabel': JSON.stringify(gaObject)
                                    });

                                // after permissions have been fetched redirect to default page
                                ctx.staticObjects.redirectToDefault(ctx.redirectTo);
                            })
                            .error(function () {
                                ctx.staticObjects.errorCallback.apply(ctx.staticObjects, arguments);
                            });
                    });
                }
            })
                .error((data, status, headers, config) => {
                    var error = data['error'];
                    var username = "";
                    var template;
                    if (error === 'ClientLegalAgreementNotAccepted') 
                        template = 'ClientLegalAgreement.html';

                    if (error === 'ProspectLegalAgreementNotAccepted') 
                        template = 'ProspectLegalAgreement.html';

                    if (ctx.usercredentials.hasOwnProperty("username")) 
                        username = ctx.usercredentials.username;
                    else 
                        username = headers("username");

                    if (template) {
                        var modalInstance = ctx.$modal.open({
                            templateUrl: '/Views/Login/' + template,
                            controller: 'LegalAgreementController',
                            size: 'lg',
                            backdrop: 'static',
                            resolve: {
                                username: () => username
                            }
                        });

                        modalInstance.result
                            .then((isLegalAgreementAccepted: boolean) => {
                                if (isLegalAgreementAccepted) {
                                    if (ctx.$location.url() !== "/iplogin")
                                        ctx.login();
                                    else {
                                        var promise = ctx.AuthenticationService.loginWithIp();
                                        ctx.processPromiseAuthData(promise, true);
                                    }
                                } else {
                                    ctx.usercredentials.errorMessage = '';
                                }
                            })
                            .catch((...args) => {
                                ctx.staticObjects.errorCallback.apply(ctx.staticObjects, args);
                            });
                    }

                    var code = parseInt(data['error_description']);
                    ctx.usercredentials.errorMessage = ctx.staticObjects.getErrorMesageByStatusCode(500, { code: code || data['error'] });
                });
        }

        public forgotPassword() {
            var ctx = this;

            var emailRegularExpression = /\w+([-+.']\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*/;
            var emailTest = emailRegularExpression.test(ctx.usercredentials.forgotPasswordEmail.toLowerCase());

            if (!emailTest) {
                ctx.usercredentials.errorMessage = "Please enter a valid email address.";
                return;
            }          
            ctx.submitClass = "loadSpinner";

            ctx.AuthenticationService.forgotPassword(ctx.usercredentials.forgotPasswordEmail)
                .success(() => {
                    ctx.usercredentials.errorMessage = "";
                    ctx.staticObjects.redirectToLink("/forgotPasswordConfirmation");
                })
                .error((data, status, headers, config) => {
                    ctx.usercredentials.errorMessage = ctx.staticObjects.getErrorMesageByStatusCode(status, data);
                });
        }

        public setPassword() {
            var ctx = this;

            var setPassword: Auth.SetPassword = { username: ctx.usercredentials.username, password: ctx.usercredentials.password };

            ctx.submitClassLast = "loadSpinner";

            ctx.AuthenticationService.setPassword(setPassword)
                .success(() => {
                    ctx.usercredentials.errorMessage = "";
                    ctx.AuthenticationService.profile()
                        .success((userInfo: Common.IUserInfo) => {
                           ctx.staticObjects.redirectToLink("/passwordChangeConfirmation");
                        })
                        .error(function () {
                            ctx.staticObjects.errorCallback.apply(ctx.staticObjects, arguments);
                        });
                })
                .error((data, status, headers, config) => {
                    ctx.usercredentials.errorMessage = ctx.staticObjects.getErrorMesageByStatusCode(status, data);
                });
        }

        public changePassword(oldPassword: string, newPassword: string) {
            var ctx = this;

            var changePassword: Auth.ChangePassword = { username: ctx.usercredentials.username, oldPassword: oldPassword, newPassword: newPassword };

            ctx.submitClassLast = "loadSpinner";

            ctx.AuthenticationService.changePassword(changePassword)
                .success(() => {
                    ctx.usercredentials.errorMessage = "";
                    ctx.AuthenticationService.profile()
                        .success((userInfo: Common.IUserInfo) => {
                            ctx.staticObjects.redirectToLink("/passwordChangeConfirmation");
                        })
                        .error(function () {
                            ctx.staticObjects.errorCallback.apply(ctx.staticObjects, arguments);
                        });
                })
                .error((data, status, headers, config) => {
                    ctx.usercredentials.errorMessage = ctx.staticObjects.getErrorMesageByStatusCode(status, data);
                });
        }

        private minimumLength() {
            var ctx = this;

            this.$scope.changePasswordForm.passwordBox.$setValidity("PasswordLength", ctx.usercredentials.password.length > 6);

            return ctx.usercredentials.password.length > 6;
        }

        private hasCapital() {
            var ctx = this;

            var regexp = /(?=.*[A-Z])/;

            this.$scope.changePasswordForm.passwordBox.$setValidity("PasswordDoesNotHaveCapital", regexp.test(ctx.usercredentials.password));

            return regexp.test(ctx.usercredentials.password);
        }

        private hasNumber() {
            var ctx = this;

            var regexp = /(?=.*[0-9])/;
            this.$scope.changePasswordForm.passwordBox.$setValidity("PasswordDoesNotHaveNumber", regexp.test(ctx.usercredentials.password));

            return regexp.test(ctx.usercredentials.password);
        }

        private passwordMatch() {
            var ctx = this;

            this.$scope.changePasswordForm.passwordBox.$setValidity("PasswordDoesNotMatch", ctx.usercredentials.password == ctx.usercredentials.confirmPassword);
            return ctx.usercredentials.password == ctx.usercredentials.confirmPassword && ctx.usercredentials.password.length > 0
        }

        private invalidCharacters() {
            var ctx = this;

            var regexp = /(^.*?(?=[&'"<>+{}]).*$)/;
            this.$scope.changePasswordForm.passwordBox.$setValidity("PasswordHasInvalidCharacter", !regexp.test(ctx.usercredentials.password));

            return regexp.test(ctx.usercredentials.password);
        }

        private activateSignalR() {
            var ctx = this;

            $.connection.hub.start()
                .done(() => {
                })
                .fail(error => {
                    alert(error.message);
                });
        }
    }

    export var accountControllerName = 'AccountController';

    angular.module(securityLoginModuleName).controller(accountControllerName, [
        '$q', '$timeout', '$scope', 'RoutingService', '$location', '$rootScope', 'AuthenticationService',
        'notificationFactory', 'staticObjects', 'UserInfoService', '$window', '$modal', AccountController]);
}
